package cn.cdeden.resource.unified.controller;

import cn.cdeden.common.core.domain.R;
import cn.cdeden.common.core.exception.ServiceException;
import cn.cdeden.common.oss.enumd.OssModuleOperate;
import cn.cdeden.common.satoken.utils.LoginHelper;
import cn.cdeden.common.web.core.BaseController;
import cn.cdeden.resource.api.domain.*;
import cn.cdeden.resource.domain.vo.SysOssVersionVo;
import cn.cdeden.resource.service.ISysOssVersionService;
import cn.cdeden.resource.unified.domain.dto.*;
import cn.cdeden.resource.unified.service.RemoteUploadFileFilter;
import cn.cdeden.resource.unified.service.UnifiedFileUploadService;
import cn.cdeden.resource.utils.FileUtil;
import cn.cdeden.system.api.RemoteUserService;
import cn.cdeden.system.api.model.LoginUser;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.io.*;
import java.util.Arrays;
import java.util.List;


/**
 * 文件统一的处理上传模块 下载
 *
 * @ProjectName : KnowCore01
 * @Package : cn.cdeden.resource.updateFile.controller
 * @ClassName : UploadFileController
 * @Author : Yu.
 * @Description : //
 * @Date : 2024/12/4 15:36
 * @Version : 1.0
 */
@Slf4j
@Validated
@RequiredArgsConstructor
@RestController
@RequestMapping("/oss/file/date")
public class UnifiedFileUploadController extends BaseController {



    private final RemoteUploadFileFilter unificationFile;

    private final UnifiedFileUploadService fileUploadService;


    private final ISysOssVersionService ossVersionService;

    @DubboReference
    private final RemoteUserService userService;


    /**
     * 验证数据是否正确
     *
     * @param uploadDto
     * @return cn.cdeden.common.core.domain.R
     * @author Yu.
     * @Date 2024/12/5 13:40
     **/
    @PostMapping(value = "/verifyData")
    public R verifyData(@Validated @RequestBody RemoteOssUpload uploadDto) {
        LoginUser loginUser = LoginHelper.getLoginUser();  //获取用户信息

        String fileName = FileUtil.getPrefix(uploadDto.getFileName()); //文件名
        uploadDto.setFileName(fileName);
        RemoteOssUpload remoteOssUpload;
        try {
            remoteOssUpload = unificationFile.verifyData(uploadDto, loginUser.getUserId(), uploadDto.getType());
        } catch (Exception e) {
            return R.fail(e.getMessage());
        }
        return R.ok(remoteOssUpload);
    }


    /**
     * 文件上传、分片上传
     **/

    /**
     * 单文件上传
     *
     * @param uploadDto
     * @return cn.cdeden.common.core.domain.R
     * @author Yu.
     * @Date 2024/12/5 13:40
     **/
    @PostMapping(value = "/upload/ordinary")
    public R upload(@Validated @ModelAttribute FilesUploadDto uploadDto) {
        return fileUploadService.upload(uploadDto);
    }


    @PostMapping(value = "/upload/cover/image")
    public R uploadCoverImage(@Validated @ModelAttribute FilesCoverUploadDto uploadDto) {
        return fileUploadService.uploadCoverImage(uploadDto);
    }



    /**
     * 创建分片信息
     *
     * @param uploadDto
     * @return cn.cdeden.common.core.domain.R
     * @author Yu.
     * @Date 2024/12/5 13:40
     **/
    @PostMapping(value = "/create/slice")
    public R createMultipartUpload(@Validated @ModelAttribute SliceFileUploadDto uploadDto) {
        return fileUploadService.createMultipartUpload(uploadDto);
    }


    /**
     * 上传分片文件
     *
     * @param uploadDto
     * @return cn.cdeden.common.core.domain.R
     * @author Yu.
     * @Date 2024/12/22 17:06
     **/
    @PostMapping(value = "/upload/slice")
    public R uploadSlice(@Validated @ModelAttribute SliceFileUploadDto uploadDto) {
        return fileUploadService.uploadSlice(uploadDto);
    }


    /**
     * 中止分片文件上传
     *
     * @param sliceId
     * @return cn.cdeden.common.core.domain.R
     * @author Yu.
     * @Description //
     * @Date 2024/12/22 16:44
     **/
    @PostMapping(value = "/abort/slice/{sliceId}")
    public R abortSliceFileUpload(@PathVariable("sliceId") String sliceId) {
        LoginUser loginUser = LoginHelper.getLoginUser(); //获取用户信息
        fileUploadService.abortSliceFileUpload(loginUser, sliceId);
        return R.ok();
    }


    /*******************************************下载************************************************/


    /**
     * 下载文件
     *
     * @param uploadDto
     * @param request
     * @param response
     * @return void
     * @author Yu.
     * @Date 2024/12/6 18:39
     **/
    @PostMapping(value = "/download")
    public void download(@Validated @RequestBody FilesDownloadDto uploadDto, HttpServletRequest request, HttpServletResponse response) {
        LoginUser loginUser = LoginHelper.getLoginUser(); //获取用户信息
        String type = uploadDto.getType(); //当前模块
        ////有问题的数据直接抛出异常即可
        List<RemoteFilesDownload> downloads = unificationFile.downloadFile(uploadDto.getStorageIds(), loginUser.getUserId(), uploadDto.getInfo(), type);
        try {
            fileUploadService.download(downloads, type, request, response);
        } catch (IOException e) {
            throw new RuntimeException("无法下载文件");
        }
    }



    /**
     * 下载历史版本
     *
     * @param uploadDto
     * @param request
     * @param response
     * @return void
     * @author Yu.
     * @Date 2024/12/6 18:39
     **/
    @PostMapping(value = "/downloadVersion")
    public void downloadVersion(@Validated @RequestBody FilesDownloadVersionDto uploadDto, HttpServletRequest request, HttpServletResponse response) {
        LoginUser loginUser = LoginHelper.getLoginUser(); //获取用户信息
        String type = uploadDto.getType(); //当前模块
        ////有问题的数据直接抛出异常即可
        List<RemoteFilesDownload> downloads = unificationFile.downloadFile(Arrays.asList(uploadDto.getStorageId()), loginUser.getUserId(), uploadDto.getInfo(), type);
        if (downloads.size() != 1) {
            throw new ServiceException("无法下载文件的历史版本,错误的参数值");
        }
        String versionId = uploadDto.getVersionId();
        SysOssVersionVo versionId1 = ossVersionService.getByIdAndVersionId(Long.valueOf(downloads.get(0).getStorageId()), versionId);//获取版本信息
        if (versionId1 == null) {
            throw new ServiceException("无法下载文件的历史版,本错误的参数值");
        }

        downloads.get(0).setVersionId(versionId);
        try {
            fileUploadService.download(downloads, type, request, response);
        } catch (IOException e) {
            throw new ServiceException("无法下载文件");
        }
    }





    /***************************************文件打印接口**********************************************************/


    /**
     * 文件打印
     * 文件转成 pdf 流方式返回前端
     *
     * @param printFileDto
     * @return void
     * @Date 2024/12/12 17:16
     **/
    @PostMapping(value = "/print")
    public void print(@RequestBody OnlinePreviewInfoDto printFileDto, HttpServletResponse response) {
        String type = printFileDto.getType();
        LoginUser loginUser = LoginHelper.getLoginUser();
        RemoteFile fileDataInfo = unificationFile.getFileDataInfo(printFileDto.getModuleId(), loginUser.getUserId(), printFileDto.getInfo(), OssModuleOperate.print, type);
        fileUploadService.convertPdf(fileDataInfo, printFileDto, response);

    }

    /**
     * 查询打印接口
     */


    /*****************************************文件测试接口************************************************************/


//    @DubboReference(check = false)
//    private final RemoteFileService fileService;
//
//    /**
//     * 文件测试接口复制
//     *
//     * @param info
//     * @return
//     */
//    @PostMapping(value = "/copyFile")
//    public R copyFile(@Validated @RequestBody OnlinePreviewInfoDto info) {
//        String type = info.getType();
//        RemoteFile dataInfo = unificationFile.getFileDataInfo(info.getModuleId(), LoginHelper.getUserId(), info.getInfo(), OssModuleOperate.Version_DownloadRecord, type); //获取文件的的信息
//        RemoteFile remoteFile = fileService.copyFile(dataInfo, OssBucketOneEnum.PUBLIC_IMAGES.getCode(), OssModuleType.public_images);
//        return R.ok(remoteFile);
//    }
//
//
//    /**
//     * 测试
//     * @author Yu.
//     * @Date 2024/12/22 16:57
//     * @param path
//     * @return cn.cdeden.common.core.domain.R
//     **/
//    @ResponseBody
//    @PostMapping(value = "/assemblyData")
//    public R assemblyData(String path) throws Exception {
//        String substring = StringUtils.substring(path, 0, path.lastIndexOf("."));
//        int sliceSize = 1024 * 1024 * 5;
//        int fileCount = sliceFile(path, substring, sliceSize);
//        SliceFileUploadDto uploadDto = new SliceFileUploadDto();
//        String eTag =  null;
//        try {
//            File file = new File(path);
//            String name = file.getName();
//            String fileName = FileUtil.getPrefix(name); //文件名
//            //// 检查文件格式是否正确
//            String extName = FileProcessingUtil.extName(name); //文件拓展名
//            //创建分片信息
//            uploadDto.setFileSize(file.length());
//            uploadDto.setPartSize(sliceSize);
//            uploadDto.setFileName(fileName);
//            uploadDto.setSuffix(extName);
//            uploadDto.setFileMd5("-1");
//            uploadDto.setType(OssModuleType.Temporary.getCode());
//            R upload = createMultipartUpload(uploadDto);
//            SysOssSliceVo data = (SysOssSliceVo) upload.getData();
//            eTag = String.valueOf(data.getSliceId());
//            if (eTag.isEmpty()) {
//                throw new RuntimeException("文件分片失败");
//            }
//            uploadDto.setSliceId(eTag);
//        }catch (Exception e){
//            log.error("创建分类文件分片失败", e);
//            throw new RuntimeException("创建分类文件分片失败");
//        }
//        int i = 1;
//        try {
//            for ( i = 1 ; i <= fileCount; i++) {
//                uploadDto.setPartNumber(i);
//                String pathname = substring + File.separator + "_" + i;
//                FileInputStream input = new FileInputStream(new File(pathname));
//                MultipartFile multipartFile = new MockMultipartFile("file"+i, input);
//                uploadDto.setFile(multipartFile);
//                uploadSlice(uploadDto);
//            }
//        }catch (Exception e){
//            abortSliceFileUpload(eTag); //中止分片上传
//            log.error("分片上传失败,"+i, e);
//            throw e;
//        }
//
//        return R.ok();
//    }
//
//
//
//    public static int sliceFile(String inputFile, String outputDir, long sliceSize) throws IOException {
//        File input = new File(inputFile);
//        File outputDirFile = new File(outputDir);
//        if (!outputDirFile.exists()) {
//            outputDirFile.mkdirs();
//        }
//
//        long totalSize = input.length();
//        System.out.println("文件总大小：" + totalSize);
//
//        // 设置单个分片大小，为了便于调试，做成25kb一个切片
//
//        // 判断总分片数量
//        int totalChunks = (int) (totalSize/sliceSize + (totalSize%sliceSize == 0 ? 0 : 1));
//        for (int i = 1; i <= totalChunks; i ++) {
//            File sliceFile = fileSlice(input,outputDir, sliceSize,  totalChunks, i);
//            System.out.println(sliceFile.getAbsolutePath() + "======" + sliceFile.length());
//        }
//
//
//        return totalChunks;
//    }
//
//    // 文件切片
//    public static File fileSlice(File file, String outputDir,long m, int totalCount, int index) {
//        FileInputStream in;
//        FileOutputStream out;
//        FileChannel inChannel;
//        FileChannel outChannel;
//        File templateFile = null;
//        try {
//            in = new FileInputStream(file);
//            inChannel = in.getChannel();
//
//            // 创建临时文件，并保持每个分片的文件名和原始文件名相同
//            String t = outputDir+ File.separator + "_" + index;
//            templateFile = new File(t);
//            out = new FileOutputStream(templateFile);
//            outChannel = out.getChannel();
//            // 从inChannel的m*i处，读取固定长度的数据，写入outChannel
//            if (index != totalCount) {
//                inChannel.transferTo(m * (index - 1), m, outChannel);
//            } else {
//                // 最后一个文件，大小不固定，所以需要重新计算长度
//                inChannel.transferTo(m * (index-1), (file.length() - m * (index-1)), outChannel);
//            }
//
//        } catch (Exception e) {
//            e.printStackTrace();
//        }
//        return templateFile;
//    }


}
